読者です 読者をやめる 読者になる 読者になる

tmytのらくがき

個人の日記レベルです

Push Notificationを使う!!

RTMしたのでPush Notificationも安心して使えますね!!!!

ということでPush Notificationを使ってみたのでめもめも。

とりあえず手始めにToastを使って、自分に@が飛んでくると通知してくれるTwitter廃人向けなアプリ&サービスを作ってみました。

とりあえず実装

まずはクライアント側。

// こんな感じで定義してあるとします。
private static readonly string PushNotificationServiceName = "PushNotification.1";
private static readonly string PushNotificationServerName = "example.com";
private static readonly string PushNotificationRegisterUrl = "http://{0}/notify/regist?m={1}&channel={2}";
HttpNotificationChannel _channel;
// コンストラクタあたりでこんな感じで初期化。
public MainPage()
{
    // すでに登録済みのチャネルがあるか探してみる。
    // なければインスタンスを生成
    if ((_channel = HttpNotificationChannel.Find(PushNotificationServiceName)) == null)
    {
        _channel = new HttpNotificationChannel(PushNotificationServiceName, PushNotificationServerName);
        _channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(_channel_ChannelUriUpdated);
    }
    _channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(_channel_ErrorOccurred);
    _channel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(_channel_ShellToastNotificationReceived);
    _channel.Open();
}

// イベントはてきとーにハンドリングします
void _channel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
{
    // Receive Shell Toast Notification
}

void _channel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
{
    // Error Occurred
}

void _channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
    // Channel URI Updated
    WebClient wc = new WebClient();
    string channelUri = _channel.ChannelUri.ToString();
    _channel.BindToShellToast();
    wc.DownloadStringAsync(new Uri(string.Format(PushNotificationRegisterUrl, PushNotificationServerName, "regist", HttpUtility.UrlEncode(channelUri))));
}

クライアントはToast Notificationを受けるだけならこれだけ。サーバへのURL通知はDownloadStringAsyncでてきとーに。

さてこっからサーバ側。サーバ側もChannelUriにデータPOSTすればいいだけなので別にたいしたことないです。が、CTP/Beta/RTMとサーバの仕様が… 最新のRTMではこんなかんじです。

POST HTTP/1.0
Host:
Content-Type: text/xml
Content-Length:
X-MessageID:
X-NotificationClass:
X-WindowsPhone-Target: toast





title
subtext

こういうリクエストを投げつけるとデバイスにPushされます。Betaの時はPayloadにもヘッダが必要でX-WindowsPhone-Targetとかが2回必要でしたがRTMではまともな感じになりました。

これをPHPで投げつけるとこんな感じです。

<?php
function pushToast($url, $text1, $text2)
{
    $opt = array(
            'headers' => array(
                'X-MessageID' => uuid(),
                'X-NotificationClass' => '2',
                'Content-Type' => 'text/xml',
                'X-WindowsPhone-Target'=>'toast'
                )
            );

    $toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
        "<wp:Notification xmlns:wp=\"WPNotification\">" .
        "<wp:Toast>" .
        "<wp:Text1>$text1</wp:Text1>" .
        "<wp:Text2>$text2</wp:Text2>" .
        "</wp:Toast>" .
        "</wp:Notification>";

    $result = http_post_data($url, $toastMessage, $opt);
    echo $result;
}
?>

X-NotificationClassヘッダにはいつデバイスに通知するかを設定できます。この値は3種類あり、値とそれぞれの意味は以下の通りです。

意味
2 データが到着次第、すぐにデバイスに通知する
12 データ到着後、450秒以内にデバイスに通知する
22 データ到着後、900秒以内にデバイスに通知する

使い方をまとめると

クライアント
  1. すでに登録されてるHttpNotificationChannelを検索
    • 無ければ生成
  2. HttpNotificationChannel::Openでチャネルを開く
  3. ChannelUriUpdatedイベントを捕まえてChannelUriをPushするデータをもってるサーバにどないかして伝える
サーバ
  1. PushしたくなったらChannelUriにXMLをPostする

以上Toast Notificationを使ってみました。