Skip to content

Instantly share code, notes, and snippets.

@yatatsu
Last active August 29, 2015 14:05
Show Gist options
  • Save yatatsu/367402303199c8919a6d to your computer and use it in GitHub Desktop.
Save yatatsu/367402303199c8919a6d to your computer and use it in GitHub Desktop.
What's New in iOS Notifications

What's New in iOS Notifications

iOS8での通知関連の変更について, WWDC2014, また以後公開されているリファレンスによる情報をまとめた.

概要

iOS8から変わる点はおおきくわけると以下の3つになる.

  1. UIUserNotificationの登場
  2. 登録/通知取得方法の変更
  3. CoreLocationを使った通知

以下, サンプルコードを示しながら説明していく.

User Notifications とは

端的にいうと新たに以下の3つのクラスが追加された. (これらのMutableなクラスも存在する)

  • UIUserNotificationAction
  • UIUserNotificationCategory
  • UIUserNotificationSettings

変更のコンセプト

  • 通知は, バナー, 通知センター, アラートなどいくつかの表現がある.
  • しかし, 通知をタップ, スワイプしたときの挙動は限定的だった. (アプリがフォアグラウンドにくる)
  • User Notification クラス群は通知に対してインタラクティヴな挙動をユーザに提供するためのクラス群.

// 画像

これによって例えばメールを受信した通知をスワイプして返信ボタンを出現させるなどができるようになる.

UIUserNotificationAction

  • 通知時に実行するボタンに対応するアクションを定義する.
  • 実際の処理に関しては知らない.

以下の様な感じでプロパティをセットする.

UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init];
acceptAction.identifier = @"ACCEPT_IDENTIFIER"; // Delegate時に渡されるID
acceptAction.title = @"Accept"; // ボタンのタイトル
acceptAction.activationMode = UIUserNotificationActivationModeBackground;
acceptAction.destructive = NO;

acceptAction.authenticationRequired = NO;
  • activationModeはバックグラウンド起動するかフォアグラウンド起動するかを設定する.
  • UIを表示する必要があればForeGroundとかんがえる.
  • destructiveは破壊的な実行を伴うか否か. YESだと赤色になる.
  • authenticationRequiredはデバイスがロック時にパスコードを求めるか否か.
  • これがYESでかつ, backgroundだとアンロックされないので注意.

参考までにWWDCのセッションでのデモでは,

  • 招待の承諾はUIがいらないのでbackground, destructiveはNO, 無害なので認証不要.
  • ゴミ箱へ捨てるはUIがいらないのでbackground, destructiveはYES, 捨てられると嫌なので認証必要(?)
  • 返信ボタンはUIが必要なのでForeground, destructiveはNO, 認証は必要と考えるのが妥当だが, Foregroundなのでいずれにせよ入力が必要.
    • (この設定は効果をもたない)

という感じだった.

UIUserNotificationCategory

  • Actionは通常一種類の通知に対して複数関連付けられる.
  • UIUserNotificationCategoryは複数のアクションをカテゴライズする.
UIMutableUserNotificationCategory *inviteCategory = [UIMutableUserNotificationCategory new];

inviteCategory.identifier = @"INVITE_CATEGORY"; // このIDを通知する側からも設定する
   
[inviteCategory setActions:@[acceptAction, maybeAction, declineAction] forContext:UIUserNotificationActionContextDefault];
  • UIUserNotificationActionContextはアクションを表示する際のコンテクストでDefault, minimumの二種類.
  • Defaultの場合は4つまでActionを表示できる. Minimumの場合は2つまでしか表示できない.
  • DefaultとMinimalでそれぞれsetAction:できる. そうするとアラート時は4つ, ほかは2つとかにできる.

UIUserNotificationSettings

  • 通知のタイプやアクションのカテゴリなどの設定情報をもつ.
  • この設定をあらかじめ登録しておくことで, 通知を受けることができる.
  • registerUserNotificationSettings:で登録するとユーザの許可を求める.
NSSet *categories = [NSSet setWithObjects:inviteCategory, nil];
UIUserNotificationType types = (UIUserNotificationTypeBadge |
								UIUserNotificationTypeSound |
								UIUserNotificationTypeAlert);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:categories];

[[UIApplication sharedApplication] registerUserNotificationSettings:settings];

許可が降りるとapplication:didRegisterUserNotificationSettings:が呼ばれる.

- (void)application:(UIApplication *)application
  didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    // user has allowed receiving user notifications of the following types
    UIUserNotificationType allowedTypes = [notificationSettings types];
}

現在の設定情報を取得するには, currentUserNotificationSettingsを使う. enabledRemoteNotificationTypesはdeprecatedになった.

通知の登録/取得方法の変更

UserNotificationsの導入により, 通知の登録やそのDelegate, 通知時に呼び出されるDelegateも変更/追加があった.

これまでのおさらい

~iOS6とiOS7で微妙に異なるがおよそ以下のようになっている.

  • 初回起動の場合はapplication:didFinishLaunchingWithOptions:が呼ばれる.
  • それ以外はapplication:didReceiveRemoteNotification:fetchCompletionHandler:が呼ばれる.
    • (iOS6以前はapplication:didReceiveRemoteNotification:)

くわしくは以下によくまとめられている.

通知方法の変更

Remote Notifications

  • カテゴリIDをpayloadに含める.
  • payloadのサイズが2KBに増えた.

{ "aps" : { "alert" : "You're invited!", "category" : "INVITE_CATEGORY" } }

Local Notifications

  • UILocalNotificationのプロパティに新しくcategoryが追加されたのでセットする.

通知のハンドリング

iOS8では

  • application:handleActionWithIdentifier:forLocalNotification:completionHandler:
  • application:handleActionWithIdentifier:forRemoteNotification:completionHandler:

の2つだけでOK. (旧APIだと届くのか未検証)

例としては以下のようになる.

- (void)application:(UIApplication *)application
  handleActionWithIdentifier:(NSString *)identifier
       forRemoteNotification:(NSDictionary *)userInfo
           completionHandler:(void (^)())completionHandler
{
    if ([identifier isEqualToString:@"ACCEPT_IDENTIFIER"]) {
        // do stuff
    }
    
    // Must be called when finished
    completionHandler();
}

リモート通知の登録

ここは変更がややこしいので概念的なところを整理.

  • これまでNotificationという概念はRemote/Localという分類のみだった.

  • が, iOS8からは別軸にUserNotification/SilentNotificationというユーザのインタラクションの有無が追加.

  • UIやユーザの承認をえるシーケンスはUserNotificationにまとめられるようになった.

  • そのためRemoteNotificationの登録方法などが分離されている.

  • 通知の種類によって別途必要な処理がある.

  • UserNotification, つまりユーザのインタラクションを介する通知(バナーとか通知センターとかいわゆるPush通知)

  • SilentNotification, iOS7以降可能になったバックグラウンド通信のみのサイレント通知

  • UserNotificationの場合はregisterUserNotificationSettings:を使って通知時にインタラクションを設定する.

  • SilentNotificationの場合はinfo.plist でUIBackgroundModesの設定が必要(Remote Notification)

  • インタラクションとの分離によって, registerForRemoteNotificationTypesはdeprecatedになった.

[[UIApplication sharedApplication] registerForRemoteNotifications];

delegate側は変わらない.

CoreLocationを使った通知

  • ある特定の場所に近づいたことをトリガーに通知できる.
  • iOS7以前も実現できたが, シンプルに実装できるようになった.
  • UILocalNotificationを使う.
  • あくまでも位置情報が有効になっているときに使える.

CoreLocationの処理は省略

UILocalNotification *locNotification = [[UILocalNotification alloc] init];
    locNotification.alertBody = @"You have arrived!";
    locNotification.regionTriggersOnce = YES;
    
    locNotification.region = [[CLCircularRegion alloc] initWithCenter:LOC_COORDINATE
                                                               radius:LOC_RADIUS
                                                           identifier:LOC_IDENTIFIER];
    [[UIApplication sharedApplication] scheduleLocalNotification:locNotification];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment