[iOS 8] CloudKit を使ってみよう (4) Push 通知を利用する

CloudKit で Push 通知

これまでレコードの保存や検索などの操作について触れてきましたが、今回は CloudKit の Push 通知機能について解説したいと思います。CloudKit はデータストレージだけではなく、このストレージを活用した Push 通知を実装することができます。何だかとっても mBaaS っぽいですね。

Push 通知を受け取ってみよう

今回は「Memo」という名前の Record Type を対象に、レコードが追加/更新/削除されたら Push 通知を送る機能を実装してみたいと思います。

Remote Notification を有効にする

まずはアプリで Remote Notification を受け取るようにしましょう。基本的にはこれまで通りの方法と一緒ですが、CloudKit を利用している場合は Certificate の登録は不要です。これ結構面倒なので嬉しいですね!

はじめに、プロジェクト設定の CapabilitiesBackground Modes を有効にし、Remote Notification にチェックします。

cloudkit-notification01

次に AppDelegate の application:didFinishLaunchingWithOptions: などで Remote Notification の認証要求処理を実装します。

import UIKit
import CloudKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
                            
    var window: UIWindow?
    
    // MARK: AppDelegate

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        
        // Remote Notification の認証要求
        var settings = UIUserNotificationSettings(
            forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Alert | UIUserNotificationType.Alert,
            categories:nil)
        application.registerUserNotificationSettings(settings)
        application.registerForRemoteNotifications()
        
        return true
    }
    
    // MARK: Remote Notification
    
    func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
        println(__FUNCTION__)
    }
    
    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        println(__FUNCTION__)
        println("deviceToken : \(deviceToken)")
    }
    
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
        println(__FUNCTION__)
    }
    
    func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
        println(__FUNCTION__)
    }

}

これで実行すると Push 通知の認証アラートが表示されます。認証されると application:didRegisterForRemoteNotificationsWithDeviceToken: が呼び出されます。

Subscription (購読) を登録する

次に Record Type を Subscription (購読) する処理を実装します。ここで Subscription した条件にマッチしたら Push 通知が届くようになります。application:didRegisterForRemoteNotificationsWithDeviceToken: を次のような処理を加えます。

    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        println(__FUNCTION__)
        println("deviceToken : \(deviceToken)")
        
        // 条件の指定
        let predicate = NSPredicate(format: "content == 'Test'")
        
        // Subscription の作成
        let subscription = CKSubscription(recordType: "Memo", predicate: predicate, options: CKSubscriptionOptions.FiresOnRecordCreation | CKSubscriptionOptions.FiresOnce)
        subscription.notificationInfo = CKNotificationInfo()
        subscription.notificationInfo.alertBody = "アイテムが追加されたし"
        
        // Subscription の登録
        let db = CKContainer.defaultContainer().privateCloudDatabase
        db.saveSubscription(subscription, completionHandler: {
            subscription, error in
            if error != nil {
                // エラー
                println("error : \(error)")
            } else {
                // 登録完了
                println("subscription : \(subscription)")
            }
        })
    }

まず条件は NSPredicate で指定します。これはレコードの検索でも登場したクラスですね。上記では「content の値が Test の場合」という条件を定義しています。

次に CKSubscription で Subscription を作成します。recordType はレコード名、predicate は上記で作成した NSPredicate オブジェクト、そして optionsCKSubscriptionOptions を指定します。CKSubscriptionOptions はレコードのどのような操作を監視するかという設定です。次の中から1つ以上設定します。

説明
CKSubscriptionOptions.FiresOnRecordCreation レコードが追加されたとき
CKSubscriptionOptions. FiresOnRecordUpdate レコードが更新されたとき
CKSubscriptionOptions.FiresOnRecordDeletion レコードが削除されたとき
CKSubscriptionOptions.FiresOnce 1度だけ通知する

通知されるメッセージは CKNotificationInfo で定義します。次のようなプロパティがセットできます。

説明
alertBody String メッセージの本文
alertLocalizationKey String メッセージの本文の Localizable.string のキー
alertLocalizationArgs Array メッセージ本文のフォーマットにセットする値の配列 (NSString, NSNumber, NSDate のいずれか)
alertActionLocalizationKey String Push 通知がアラートで表示されたときのアプリ起動ボタンのテキスト
alertLaunchImage String Push 通知からアプリを起動したときの Launch Image のファイル名
soundName String 効果音のファイル名
shouldBadge Bool true にするとバッジの数をインクリメントする
shouldSendContentAvailable Bool true にすると content-available を設定し、Push 通知を受けたときにバックグラウンド処理が実行される

最後に CKDatabase#saveSubscription を呼び出して終わりです。「content が Test の Memo レコードが追加されたとき」という条件を登録したので、これにマッチするレコードが追加されたときに Push 通知が届くようになります。

実行してみる

それでは実行してみます。Remote Notification を受け取りたいので、アプリがバックグラウンドに居る必要があります。CloudKit Dashboard からレコードを追加してみると、通知が受け取れるはずです。プライベートデータベースを対象にしている場合、追加する側と受け取る側が同じ Apple ID で試してください。

cloudkit-notification02

まとめ

サービス系のアプリを作りたいとき、Push 通知を送りたいことはよくあると思いますが、CloduKit だけで利用することができるのでとっても手軽ですね!

参考