Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

7.5 UILocalNotification

yuichi takeda edited this page May 13, 2015 · 7 revisions

この節では、ユーザーに対して通知を行う "ローカル通知" を扱います。今までの節(NSNotification)は、プログラミングのメカニズムとしての通知を扱いましたが、ここでは画面上でユーザーに何か情報を提示する通知を扱います。

img1

公式のリファレンスは Local およびPush Notificationプログラミングガイド をご覧ください。

通知の種類

ユーザーが受け取る通知にも通知の機構による違いや、表示できるコンテンツがあります。

リモート通知(Push通知) / ローカル通知

機構ごとの違いとしては、

  • サーバーから任意のタイミングで通知を送ることのできるリモート通知(Push通知とよく呼ばれています)
  • ある時刻や、ある場所に入ったときに通知されるローカル通知 。どの条件で通知を出すかはプログラム内で指定します。

の二つがあります。どちらの通知もユーザーからの見た目は同じです。

バッジ/サウンド/メッセージ

通知の見た目などでカスタマイズすることのできるものは

  • アプリアイコンの右上につくバッジの数
  • 通知を出す時のサウンド
  • 表示するメッセージ

です。iOS8からは通知に対するアクションの選択肢を表示できるオプションが追加されました。

Push通知

Push通知はサーバーからユーザーの端末に通知を届けるメカニズムです。 Push通知はiOS Developer Programに加盟していることが条件になるためこのトレーニングコースでは取り上げませんが 全体の仕組みだけ少し紹介します。

詳しくは、冒頭であげたリファレンスを参考にしてください。

Push通知送信のフロー

  • 各アプリのサーバーからAppleの通知を受け取るサービス(Apple Push Notification Service: 通称APNs)のサーバーに通知のコンテンツを送信します
  • APNsサーバーから各iOS端末に通知が送られます
  • 各端末で通知が表示されます(場合によってはアプリ内でハンドリングを行います)

Figure 3-1  Pushing a remote notification from a provider to a client app Figure 3-1 Pushing a remote notification from a provider to a client app

Local and Remote Notification Programming Guide より

補足と注意

デバイストークン

サーバーからPush通知を送る端末を指定するためにはデバイストークンを利用します。デバイストークンとはiOSから提供されるハッシュ値となり、 UIApplication#registerForRemoteNotificationsを呼んだ結果として得ることができます。

このデバイストークンを各アプリのバックエンドサーバーに保存しておき、通知を送るときに利用します。 デバイストークンは使用する度ごとに変わるものではなく、各端末、アプリごとに一意な値になっています。

サーバーからAPNsへの通知

APNsサーバーに通知を送信するには、 gateway.push.apple.com:2195 に向けて独自のバイナリプロトコルでTSLで送信します。 詳しいプロトコルの仕様などについては こちらをご覧ください。

この際、通知のコンテンツに加えて

  • どの端末に送信するかを決めるためのデバイストークン
  • どのアプリからのPush通知かを保証するための証明書(iOS Developer Centerより入手)

の2つを指定する必要があります。

このプロトコルを実装するのは骨が折れるので、外部サービスを利用したり、あるいはサードパーティのライブラリを利用することをおすすめします。例えばGemでは https://github.com/nomad/houstonなどがおすすめです。

Quality Of Service

Push通知を送った際に、ターゲットの端末の電源がOffになっていたり、圏外にいた場合は端末に到達することができません。 そのような場合、APNsでは再送を行いますが、一定量以上再送のキューが溜まった場合は古い通知から破棄されます。 そのため、Push通知は信頼性の高い通信プロトコルとして採用しないほうがよいでしょう。

UILocalNotification

UILocalNotification(ローカル通知)はサーバーを介さず、アプリから通知を送る方法です。通知は指定の時刻、あるいは指定の位置に入った時に行われます。 サーバーを介さないので何か他のユーザーのアクションを通知するといった用途には使えませんが、アプリ内で完結するので実装が比較的簡単です。

以下では、指定の時刻に通知を出す方法について解説をします。

ユーザーの許諾を得る

ユーザーに通知を送る際には、通知を送ることをユーザーが許可している必要があります。そのためまずは、ユーザーの許諾を得ることが必要になります。

ユーザーの許諾を得るためには、iOS8以降では UIApplicationの - (void)registerUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings を実行します。

UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettingssettingsForTypes:types
                                                                        categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];

ここで指定している UIUserNotificationType は通知で利用するタイプで、サウンド、バッジ、アラートの3つがあります。それぞれどの通知を送るかをオプショナルで指定します。 このタイプをUIUserNotificationSettingsで追加します。UIUserNotificationSettingsは通知をUIUserNotificationCategoryのカテゴリごとに分けるためのクラスです。カテゴリを分けることで通知から簡単なアクションを行うことができますが、ここではカテゴリを用いずnilを指定します。

このUIUserNotificationSettingsを引数として -registerUserNotificationSettings:を実行することでユーザーの許諾を得ます。 このメソッドを実行すると

img1

のようなアラートが表示されます。このアラートでユーザーが"OK"を押すと通知が許可されます。 許可された場合、appDelegateのコールバック関数 application:didRegisterUserNotificationSettings: が呼ばれます。 アラートを表示→ユーザーがアラートをタップ→コールバック関数が呼ばれる のフェーズはそれぞれ非同期で行われるので、許諾を得てすぐ次の行で通知を登録する、ということはできません。 何かしらの方法で一度通知を待機させておく必要があります。

許諾を得るのは初回のみ

一度許諾を得てしまえば、改めて通知を登録するときに許諾を得る必要はなく初回の一度のみで十分です。 そこで、許諾済みかどうかをチェックし、許諾済みでない場合にのみ許諾を得るようにします。

許諾の状態の取得には UIApplicationの - (UIUserNotificationSettings *)currentUserNotificationSettingsを利用します。 このメソッドの返り値で得られるUIUserNotificationSettingsのtypesが利用できる通知のタイプになっており、UIUserNotificationTypeNone が通知の許諾がない状態となります。 この状態の時のみ、許諾を得るようにします。

UIUserNotificationSettings *currentSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
if ( currentSettings.types == UIUserNotificationTypeNone ) {
   // ここで許諾を得る
}

UIUserNotificationTypeNoneは通知できるタイプがない状態を表しますが、これは未許諾の状態と、ユーザーが許諾を断った時の両方で該当します。iOS8 SDKではこの二つの状態を区別するメソッドはないようです。

ですが、-registerUserNotificationSettings:を実行してアラートが出るのは一度のみなので、何度もアラートが出るということはありません。

iOS7以前

-registerUserNotificationSettings:- currentUserNotificationSettings はiOS8SDK以降で利用できるメソッドになり、iOS7以前では許諾を得る必要がありません。 そのためこれらのメソッドを実行する必要はなく、むしろ実行してしまうとunrecognized selectorの例外が発生してクラッシュしてしまいます。そのため以下のようにメソッドがあるかどうかをチェックする必要があります。

if ( [[UIApplication sharedApplication] respondsToSelector:@selector(currentUserNotificationSettings)] ) {
        // iOS8SDK以降でこの場合のみ許諾を得る
} else {
        // iOS7SDK以前なので許諾を得る必要はない
}

通知を登録する

許諾を得ることができたら、通知を登録します。通知の登録は、UILocalNotificationインスタンスを作り、UIApplicationの- scheduleLocalNotification:を実行するだけです。

以下が実行のサンプルです。

// 通知のインスタンスを作成
UILocalNotification *notification = [[UILocalNotification alloc] init];

// 通知を表示する時刻
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:60*3]; // 3分後

// アラートの本文
notification.alertBody = @"This is Local Notification";

// 通知で鳴らすサウンド. アプリ内に予めインストールしておいたサウンドのファイル名を指定
notification.soundName = @"sound_file_name";

// アプリアイコンにつけるバッジの数
notification.applicationIconBadgeNumber = 3;

// アプリケーション独自に通知に関する情報をセットすることが出来る
notification.userInfo = @{@"some_id": @"foobar"};

// 通知を登録する
[[UIApplication sharedApplication] scheduleLocalNotification:notification];

UILocalNotificationの各プロパティの詳細については リファレンス を参照して下さい。

通知をハンドリングする

通知を受けてアプリケーションを起動した時に、どのような通知から起動したかを判断し、ハンドリングすることができます。 AppDelegateの特定のメソッドがコールバック関数として実行されるのですが、アプリケーションの状態を応じて呼ばれるコールバック関数が異なります。

注意

通知経由の起動時のコールバック関数はドキュメントで明記されておらず、手元の環境(iOS SDK 8.3)で実行した結果になります。 実装する場合は実際に動作を検証して下さい。

アプリケーションプロセスがあるとき

アプリケーションプロセスが実行中の場合、つまりアプリを利用中(フォアグラウンドにいる)の場合と、アプリがバックグラウンドの場合は、 - application:didReceiveLocalNotification:が呼ばれます。

引数には起動したUILocalNotificationが含まれています。

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    // 通知登録時の情報を利用したい場合はuserInfoより取り出す
    NSDictionary *userInfo = notification.userInfo;

    if (application.applicationState == UIApplicationStateActive) {
        // アプリが起動中の場合の場合のハンドリングをここに記述する
        // 通知が表示された時、即座に実行される
    } else if (application.applicationState == UIApplicationStateBackground) {
        // アプリが起動中のバックグラウンドの場合のハンドリングをここに記述する
        // 表示されたときではなく、通知をタップしたり、スワイプして起動した時に実行される
    }
}

アプリケーションプロセスがないとき

アプリケーションプロセスがない場合、つまりバックグラウンドでも動いていない時に通知をタップしたり、スワイプで起動した場合はアプリケーションプロセスの起動が行われ、そのコールバック関数の引数に通知の情報が含まれます。 アプリケーション起動時のコールバック関数は - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions です。(- application:didFinishLaunchingWithOptions: も呼び出されます。) この引数の launchOptionsは起動時のオプションなのですが、 UIApplicationLaunchOptionsLocalNotificationKey で取り出される値が通知のUILocalNotificationインスタンスになります。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    // 中略

    UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
    if (notification != nil) {
        // ローカル通知経由の場合の処理をここで行う
    }

    return YES;
}

登録している通知を操作する

既に登録済みの通知を取得するには

[[UIApplication sharedApplication] scheduledLocalNotifications];

で取り出すことができます。(リファレンス) また、ある通知を削除する場合は

[[UIApplication sharedApplication] cancelLocalNotification:notification];

で削除します。(リファレンス)

はじめに

  1. iOSについて

  2. Xcode最初のステッフ

  3. 導入

  4. Objective C の基礎

  5. メモリ管理

  6. 1.3 UIViewController1 UIViewController のカスタマイズ(xib, autoresizing)

  7. 1.3 UIViewController1 UIViewController のカスタマイズ(storyboard)

  8. UIViewController2 - ModalViewController

  9. UIViewController2 - ModalViewController(storyboard)

  10. UIViewController3 - ライフサイクル

  11. HomeWork 1 Objective C の基本文法

  12. HomeWork 2 UIViewControllerとModalViewController

  13. HomeWork 3 UIViewController + Animation

  14. UIKit 1 - container, rotate-

  15. UINavigationController

  16. UITabController

  17. Custom Container View Controller

  18. Supporting Multiple Interface Orientations

  19. HomeWork 1 - タブバーからモーダルビューを表示する

  20. HomeWork 2 - NavigationController

  21. HomeWork 2.3 デバイスことに回転対応

  22. UIKit 2- UIView -

  23. UIView

  24. UIView のカスタマイズ

  25. UIView Animation

  26. HomeWork 1 - UIScrollView

  27. UIKit 3 - table view -

  28. UITableView について

  29. UITableViewとNavigationController

  30. custom UITableViewCell の作成

  31. UITableViewのその他のオプション、カスタマイズ

  32. HomeWork 1 - Dynamic height with a custom uitableviewcell

  33. UIKit 4 - image and text -

  34. UIImagePickerController

  35. Assets Library

  36. UITextFiled, UITextView

  37. KeyboardNotification

  38. Homework 1 - フォトの複数枚選択

  39. ネットワーク処理

  40. NSURLConnection

  41. JSONのシリアライズとデシリアライズ

  42. UIWebView

  43. ローカルキャッシュと通知

  44. NSUserDefaults, Settings Bundle

  45. NSFileManager

  46. Key Value Observing

  47. NSNotification、NSNotificationCenter を用いた通知

  48. UILocalNotification

  49. Blocks, GCD

  50. Blocks

  51. GCD

  52. 【演習】GCD,-Blocksを用いたHTTPリクエストマネージャの作成

  53. 設計とデザインパターン

  54. クラス設計 1

  55. クラス設計 2

  56. [クラス設計演習] (https://github.com/mixi-inc/iOSTraining/wiki/9.3-%E3%82%AF%E3%83%A9%E3%82%B9%E8%A8%AD%E8%A8%88%E6%BC%94%E7%BF%92)

  57. 開発ツール

  58. Instruments, デバッガ

  59. CocoaPods

  60. テスト

  61. iOS開発におけるテスト

  62. GHUnit

  63. Kiwi

  64. KIF

  65. In-App Purchase

  66. In-App Purchase

  67. 付録

  68. Tips of Xcode

  69. Auto Layout 入門

  70. Auto Layout ドリル

Edit sidebar

Clone this wiki locally