iOSのRemote Notificationを試してみた

iOSのRemote Notifiacation(Apple Push Notification service:APNs)を試したので手順をメモっとく。
環境は OSX(Lion)+Xcode4.2

準備しとくこと

大まかには以下。

  1. iOS 実機でiOSアプリを動作確認できるようにする
  2. APNs可能なProvisioning Profileを準備する
  3. プロバイダ(サーバアプリ)に必要な証明書ファイルを準備する
iOS 実機でiOSアプリを動作確認できるようにする

iOSアプリを実機で動作確認しよう-プロビジョニングファイルの作成手順- | クラスメソッド開発ブログ にキレイにまとまってる。
実際にこれと同じことをやった。

ハマったことと言えば、Developer Programを登録する際のAppleIDの名前が日本語だったので、申請途中でペンディングになったこと。
申請とおらないなぁと思いつつしばらく気づかず、数日後に気づいて(名前が????になってた)、
Apple IDの名前を英語表記にしたら、数時間後Apple側で処理再開してくれったぽい。

名前や住所は英語表記に、日本語の住所をiTunesなどで使いたい場合は別アカウントのほうがいいかのかも。

あと、Organizerのサイドバーの"Provisioning Profile"で、"Automatic Device Provisioning"というのをチェックしておくと、
"Use for Development"ボタンを押した際に、自動的に登録される模様。

APNs可能なProvisioning Profileを準備する

上記のProvisioning Profileは汎用的なものなようなので、APNsが利用できない。
なので、新しくProvisioning Profileを作成し、そっちでAPNsできるようにする。

  • Provisioning Portal にいく
  • サイドバーの"App IDs"からApp IDを作成する
    • New App IDボタンから必要事項を入力する
  • 証明書を取得し、キーチェーンアクセスに登録する
    • 作成したApp IDが一覧に追加されるので、Configureボタンを押下
    • "Enable for Apple Push Notification service"のチェックボックスを押下
    • 今回は"Development Push SSL Certificate"の”Configure"ボタンを押下
      • 証明書要求ファイルは前節で作成したものを使った
      • 証明書をDLする
      • 証明書をダブルクリックしキーチェーンアクセスに登録
  • Provisioning Profile を作成
    • ProvisioningPortal でサイドバーのProvisioningを選択
    • "New Profile"ボタンから必要事項を入力
      • App IDは上で作ったものにする
    • 画面リフレッシュすると一覧に追加されているのでDL
  • Provisioning Profileを登録
プロバイダ(サーバアプリ)に必要な証明書ファイルを準備する

Macのキーチェーンアクセスとopensslで証明書を作成する

  • キーチェーンアプリを起動
  • 自分の証明書を秘密鍵を選択状態にする
    • 左上のキーチェーンを"ログイン"、左下の分類を"自分の証明書"から行くと、証明書と秘密鍵が階層になっているのでこの2つを選択
  • メニューバーの[ファイル] - [書き出す] を選択
    • フォーマット".p12"形式で書きだす
      • パスワードを何か決めて入れる
  • 以下のコマンドで"pem"形式に変換
    • openssl pkcs12 -in CertificateName.p12 -out CertificateName.pem -nodes
      • パスワード聞かれるので".p12"形式で書きだした際のパスワードを入れる

CertificateName.pem をプロバイダが使用してAPNsにアクセスする。
また、このやりかただと接続する際にパスフレーズは不要だった。

プロバイダでやんないといけないこと

大まかには以下。

  1. iOSからデバイストークンを受け取る
  2. プロバイダからAPNsに通知したい情報を送信する
    1. 通知したいデバイスのデバイストークンも渡す
    2. APNsとはSSL通信するので証明書が必要。(このへんの準備の理解があやしい)
  3. APNsからプロバイダへのフィードバックを受け取れるようにする
    1. (iOSアプリのアンインストールなどで)通知に失敗した場合など、APNsからフィードバックされる


プロバイダ側も色々あるが、今回はiOSで通知を受け取るのに必要最低限なところだけ書く。
動作確認用に、Apple Push Notification Services Tutorial: Part 1/2 にあるPHPのサンプルをプロバイダとして利用した。
なので、以下を行った。

  • iOSからデバイストークン受け取る代わりに、iOSのデバッグログからコピってコードに直接書く
  • APNsからのフィードバックはやんない
  • 先ほど準備した証明書を"ck.pem"という名前でPHPサンプル(simplepush.php)と同フォルダに置く

で、実行すると

$ php simplepush.php
Connected to APNS
Message successfully delivered

といった感じで成功した。

iOSアプリでやんないといけないこと

大まかには以下。

  1. iOSに対してAPNsにデバイストークンを登録するための依頼をする処理を書く
  2. iOSからデバイストークンを受け取ったときの処理を書く
  3. iOSからデバイストークンを受け取れなかったときの処理を書く
  4. APNsから通知を受けたときの処理を書く

以下のようなコードをApplicationDelegate.mに追記。
今回はiPod touch(4th)+iOS 5.0.1 で試し、通知を受け取ることができた。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //画面起動時の初期化がここで行われる

    //以下を追加。通知を受けたい種別を引数に渡す
     registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
                                         UIRemoteNotificationTypeSound |
                                         UIRemoteNotificationTypeAlert)];
    return YES;
}

//デバイストークン取得に成功した場合呼ばれる
- (void)application:(UIApplication *)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
{
    NSLog(@"Registration Successed. token: %@", devToken);

    //ここでプロバイダにデバイストークンを送信すべし
}

//デバイストークン取れなかった場合(シミュレータの場合ここにきた)
- (void)application:(UIApplication *)app
didFailToRegisterForRemoteNotificationsWithError:(NSError *)err
{
    NSLog(@"Error in registration. Error: %@", err);
}

//通知センタや通知ダイアログから起動すると呼ばれる
//アプリがforegroundの場合もこれが呼ばれた
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSLog(@"ReceiveRemoteNotification on foreground: %@", userInfo);
}

もっと他にも色々ありそうだけど、とりあえずここまで。