iOS8で、UILocalNotification
で登録した通知からアプリを起動するたびに、毎回消えるようになりました。
以前まで大丈夫だった状況で、消えるようになっていました。
たぶんぼくの環境だけではないと思うのですが、毎回消えるので困っていました。
以前は、通知センターに通知を残していればアプリを起動するというようなプチハックにも使えて便利だったのですが、上記のように少し挙動が変わり同じように動作させるには少しコツがあります。
考え方としては、UILocalNotification
を再度登録するだけです。
でも、通知センターから起動した場合はアプリの起動している状態によって3パターンに動作が分かれますので、それぞれに対して対応する必要があります。
パターンですが、以下のようになります。
- アプリが完全に落ちている場合。
- アプリがバックグラウンドで動作している場合。
- アプリが現在フォアグラウンドで使用中の場合。
このパターンそれぞれをアプリで取得するには、applicationDetegate
でいくつかのコードを書く必要があります。
まず、アプリが完全に落ちている場合ですが、application:didFinishLaunchingWithOptions:
が呼ばれるので、launchOptions
からUIApplicationLaunchOptionsLocalNotificationKey
キーで通知があるかどうかを調べて、存在していればnotification
を再登録します。
if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
// 通知センターから呼ばれた
}
アプリが現在フォアグラウンドで使用中の場合とアプリがバックグラウンドで動作している場合は、application:didReceiveLocalNotification:
が呼ばれます。
このときに、UIApplicationのapplicationState
で起動中かバックグラウンドから起動したのかを判別しなければなりません。以下のコードで判定できます。
if (application.applicationState == UIApplicationStateActive) {
// 起動中
}
if (application.applicationState == UIApplicationStateInactive) {
// バックグラウンドから呼び出し
}
この、パターン内で再登録すれば通知が消えずに済むのですが、バックグラウンドから呼び出したときにすぐ再登録すると削除されず、そのままで2つ登録されることになってしまいます。
理由を色々と推測しているのですが、結局のところよくわかっていません。
ライフサイクルで、application:didReceiveLocalNotification:
が終わったあとに通知が消えます。
しかし、このメソッドの中でUIApplicationのscheduleLocalNotification:
メソッドを呼ぶと、そのアプリのapplicationState
がUIApplicationStateInactive
の状態で再度application:didReceiveLocalNotification:
呼び出されることになります。
そのあたりの動作で通知センターから消えなくなって、登録だけ実行されるのでしょうか。
とりあえず、これを解決する方法はありますので早速工夫してみます。
まず、呼び出された通知を保持しておく変数を準備しておきます。
@interface AppDelegate ()
@property (nonatomic) UILocalNotification *calledNotification;
@end
これに、application:didReceiveLocalNotification:
で渡されるnotification
を入れておいて、ライフサイクルで以降に呼ばれるapplicationDidBecomeActive:
あたりで、再登録を呼び出せば、問題なく通知が消えないような動作を実現できます。
- (void)applicationDidBecomeActive:(UIApplication *)application{
if (_calledNotification) {
[application scheduleLocalNotification:_calledNotification];
}
_calledNotification = nil;
}
アプリの内容によっては、applicationDidEnterBackground:
でアプリを閉じるタイミングで再登録してもいいですし、一度全ての通知を解除して必要な分を再登録するというアプローチでも良いと思います。
冒頭で述べたとおり、以前は、通知センターからアプリを起動するというようなテクニックが流行っていましたがiOS 8ではTodayウィジェットがありアプリのショートカットとして通知センターを使うのはもう必要がないかも知れません。